home *** CD-ROM | disk | FTP | other *** search
- .!****************************************************************************
- .!
- .! ANTIC PUBLISHING INC., COPYRIGHT 1985. REPRINTED BY PERMISSION.
- .!
- .! ** Professional GEM ** by Tim Oren
- .!
- .! Proff File by ST enthusiasts at
- .! Case Western Reserve University
- .! Cleveland, Ohio
- .! uucp : decvax!cwruecmp!bammi
- .! csnet: bammi@case
- .! arpa : bammi%case@csnet-relay
- .! compuserve: 71515,155
- .!
- .!****************************************************************************
- .!
- .!
- .!****************************************************************************
- .!
- .! Begin Part 3
- .!
- .!****************************************************************************
- .!
- .PART III THE DIALOG HANDLER
- .SH A MEANINGFUL DIALOG
- This issue of ST PRO GEM begins an exploration of ST GEM's dialog handler. I
- will discuss basic system calls for presenting the dialog, and then continue
- with techniques for initializing and reading on/off button and "radio" button
- objects. We will also take some short side-trips into the operation
- of the GEM Resource Construction Set to assist you in building these dialogs.
- .PP
- There are a number of short C routines which accompany this column. These are
- stored as file GEMCL3.XMO in DL 5 on SIG*ATARI. Before reading this column, you
- should visit SIG*ATARI (go pcs-132) and download this file.
- .PP
- .SH DEFINING TERMS
- A dialog box is an "interactive form" in which the user may enter text and
- indicate selections by pointing with the mouse. Dialogs in GEM are
- "modal", that is, when a dialog is activated other screen functions
- such as menus and window controls are suspended until the dialog is completed.
- .PP
- In most cases, the visual structure of a GEM dialog is specified within your
- application's resource file. The GEM Resource Construction Set (RCS)
- is used to build a picture of the dialog.
- .PP
- When the RCS writes out a resource, it converts that picture into a tree of
- GEM drawing objects and stores this data structure within the resource. Before
- your application can display the dialog, it must load this resource file and
- find the address of the tree which defines the dialog.
- .PP
- To load a resource, the AES checks its size and allocates memory for the
- load. It then reads in the resource, adjusting internal pointers to
- reflect the load address. Finally, the object sizes stored in the
- resource are converted from characters to pixels using the system font size.
- .PP
- A note for those with Macintosh experience: Although Mac and GEM resources
- share a name, there are fundamental differences which can be misleading. A Mac
- resource is a fork within a file; a GEM resource is a TOS file by itself. Mac
- resources may be paged in and out of memory; GEM resources are monolithic. GEM
- resources are internally tree structured; Mac resources are not. Finally, Mac
- resources include font information, while ST GEM does this with font loading at
- the VDI level.
- .PP
- The resource load is done with the GEM AES call:
- .FB rsrc_load()
- ok = rsrc_load(ADDR("MYAPP.RSC"));
- .FE
- "MYAPP" should be replaced with the name of your program. Resources
- conventionally have the same primary name as their application, with the RSC
- extent name instead of PRG. The ok flag returned by rsrc_load will be FALSE is
- anything went wrong during the load.
- .PP
- The most common causes of failure are the resource not being in the
- application's subdirectory, or lack of sufficient memory for GEM to allocate
- space for the resource. If this happens, you must terminate the program
- immediately.
- .PP
- Once you have loaded the resource, you find the address of a dialog's object
- tree with:
- .FB rsrc_gaddr()
- rsrc_gaddr(R_TREE, MYDIALOG, &tree);
- .FE
- Tree is a 32-bit variable which will receive the address of the root
- node of the tree.
- .PP
- The mnemonic MYDIALOG should be replaced with the name you gave your dialog
- when defining it in the RCS. At the same time that it writes the resource, RCS
- generates a corresponding .H file containing tree and object names.
- In order to use these mnemonics within your program, you must include
- the name file in your compile: #include "MYAPP.H"
- .SH BUG ALERT!
- When using the DRI/Alcyon C compiler, .H files must be in the compiler's home
- directory or they will not be found. This is especially annoying using a two
- floppy drive ST development system. The only way around this is to explicitly
- reference an alternate disk in the #include, for instance: "B:MYAPP.H".
- [Ed. Note: Use the -i flag with the C pre-processor to name the include
- directories].
- .PP
- Now that the address of the dialog tree has been found, you are ready to
- display it. The standard (and minimal) sequence for doing so is given in
- routine hndl_dial() in the download. We will now walk through each
- step in this procedure.
- .PP
- The form_center call establishes the location of the dialog on the screen.
- Dialog trees generated by the RCS have an undefined origin (upper-left corner).
- .PP
- Form_center computes the upper-left location necessary to center the dialog
- on the screen, and inserts it into the OB_X and OB_Y fields of the ROOT object
- of the tree. It also computes the screen rectangle which the dialog
- will occupy on screen and writes its pixel coordinates into variables
- xdial, ydial, wdial, and hdial.
- .PP
- There is one peculiarity of form_center which occasionally causes trouble.
- Normally the rectangle returned in xdial, etc., is exactly the same size as the
- basic dialog box.
- .PP
- However, when the OUTLINED enhancement has been specified for the box,
- form_center adds a three pixel margin to the rectangle returned. This
- causes the screen area under the outline to be correctly redrawn later
- (see below). Note that OUTLINED is part of the standard dialog box in
- the RCS. Other enhancements, such as SHADOWED or "outside" borders
- are NOT handled in this fashion, and you must compensate for them in
- your code.
- .PP
- The next part of the sequence is a form_dial call with a zero parameter.
- This reserves the screen for the dialog action about to occur. Note that the C
- binding given for form_dial in the DRI documents is in error: there are nine
- parameters, not five. The first set of xywh arguments is actually used with
- form_dial calls 1 and 2 only, but place holders must be supplied in all cases.
- .PP
- The succeeding form_dial call (parameter one) animates a "zoom box" on the
- screen which moves and grows from the first screen rectangle given to
- the second rectangle, where the dialog will be displayed.
- .PP
- The use of this call is entirely optional. In choosing whether to use it or
- not, you should consider whether the origin of the "zoom" is relevant to the
- operation. For instance, a zoom from the menu bar is relatively meaningless,
- while a zoom from an object about to be edited in the dialog provides visual
- feedback to the user, showing whether the correct object was chosen.
- .PP
- If the origin is not relevant, then the zoom is just a time-waster. If you
- decide to include these effects, consider a "preferences" option in your app
- which will allow the experienced and jaded user to turn them off in the
- interests of speed.
- .PP
- The objc_draw call actually displays the dialog on the screen. Note that the
- address of the tree, the beginning drawing object, and the drawing depth are
- passed as arguments, as well as the rectangle allotted for the dialog.
- .PP
- In general, dialogs (and parts of dialogs) are ALWAYS drawn beginning at the
- ROOT (object zero). When you want to draw only a portion of the
- dialog, adjust the clipping rectangle, but not the object number.
- This ensures that the background of the dialog is always drawn correctly.
- .PP
- The objc_xywh() utility in the download can be used to find the clipping
- rectangle for any object within a dialog, though you may have to allow an extra
- margin is you have used shadows, outlines, or outside borders with the object.
- .PP
- Calling form_do transfers control to the AES, which animates the dialog for
- user interaction. The address of the dialog tree is passed as a
- parameter. The second paramter is the number of the editable object
- at which the text cursor will first be positioned. If you have no text
- fields, pass a zero. Note that again the DRI documents are in error:
- passing a -1 default may crash the system. Also be careful that the
- default which you specify is actually a text field; no error checking
- is performed.
- .PP
- The form_do call returns the number of the object on which the clicked to
- terminate the dialog. Usually this is a button type object with the EXIT and
- SELECTABLE attributes set. Setting the DEFAULT attribute as well will cause an
- exit on that object is a carriage return is struck while in the dialog.
- .PP
- If the top bit of the return is set, it indicates that the exit object had
- the TOUCHEXIT attribute and was selected with a double-click. Since very few
- dialogs use this combination, the sample code simply masks off the top bit.
- .PP
- The next form_dial call reverses the "zoom box", moving it from the dialog's
- location back to the given x,y,w,h. The same cautions apply here as above.
- .PP
- The final form_dial call tells GEM that the dialog is complete, and that the
- screen area occupied by the dialog is now considered "dirty" and needs to be
- redrawn. Using the methods described in our last column, GEM then
- sends redraws to all windows which were overlaid, and does any
- necessary redrawing of the menu or desktop itself.
- .PP
- There is one notable "feature" of form_dial(3): It always redraws an area
- which is two pixels wider and higher than your request! This was probably
- included to make sure that drop-shadows were cleaned up, and is usually
- innocuous.
- .SH A HANDY TRICK
- Use of the form_dial(3) call is not limited to dialogs. You can use
- it to force the system to redraw any part of the screen. The
- advantage of this method is that the redraw area need not lie entirely
- within a window, as was necessary with the send_redraw method detailed
- in the last column. A disadvantage is that this method is somewhat
- slower, since the AES has to decide who gets the redraws.
- .SH CLEAN UP
- As a last step, you need to clear the SELECTED flag in the object which was
- clicked. If you do not do this, the object will be drawn inverted the next
- time you call the dialog. You could clear the flag with the GEM objc_change
- call, but it is inefficient since you do not need to redraw the object.
- .PP
- Instead, use the desel_obj() code in the download, which modifies the
- object's OB_STATE field directly. Assuming that ret_obj contains the exit
- object returned by hndl_dial, the call:
- .FB desel_obj()
- desel_obj(tree, ret_obj);
- .FE
- will do the trick.
- .SH RECAP
- The basic dialog handling method I have described contains three steps:
- initialization (rsrc_gaddr), dialog presentation (hndl_dial), and cleanup
- (desel_obj).
- .PP
- As we build more advanced dialogs, these same basic steps will be performed,
- but they will grow more complex. The initialization will include setting up
- proper object text and states, and the cleanup phase will also interrogate the
- final states of objects to find out what the user did.
- .SH BUTTON, BUTTON
- The simple dialogs described above contain only exit buttons as active objects.
- As such, they are little more than glorified alert boxes.
- .PP
- We will now increase the complexity a little by considering non-exit buttons.
- These are constructed by setting the SELECTABLE attribute on a button object.
- At run-time, such an object will toggle its state between selected
- (highlighted) and non-selected whenever the user clicks on it. (You
- can set the SELECTABLE attribute of other types of objects and use
- them instead of actual buttons, but be sure that the user will be
- able to figure out what you intend!)
- .PP
- Having non-exit buttons forces us to consider the problem of initializing
- them before the dialog, and interrogating and resetting them afterward.
- .PP
- Since a button is a toggle, it is usually associated with a flag variable in
- the program. As part of the initialization, you should test the flag variable,
- and if true call:
- .FB sel_obj()
- sel_obj(tree, BTNOBJ);
- .FE
- which will cause the button to appear highlighted when the dialog is first
- drawn. Sel_obj() is in the download. BTNOBJ is replaced with the name you
- gave your button when you defined it in the RCS. Since the button starts out
- deselected, you don't have to do anything if your flag variable is false.
- .PP
- After the dialog has completed, you need to check the object's state. The
- selectp() utility does so by masking the OB_STATE field. You can simply assign
- the result of this test to your flag variable, but be sure that the dialog was
- exited with an OK button, not with a CANCEL! Again, remember to clean up the
- button with desel_obj(). (It's often easiest to deselect all buttons
- just before you leave the dialog routine, regardless of the final
- dialog state.)
- .SH WHO'S GOT THE BUTTON?
- Another common use of buttons in a dialog is to select one of a set
- of possible options. In GEM, such objects are called radio buttons.
- This term recalls automobile radio tuners where pushing in one button
- pops out any others. In like fashion, selecting any one of a set of
- radio buttons automatically deselects all of the others.
- .PP
- To use the radio button feature, you must do some careful work with the
- Resource Construction Set.
- .PP
- First, each member of a set of radio buttons must be children of the same
- parent object within the object tree. To create this structure, put a hollow
- box type object in the dialog, make it big enough to hold all of the buttons,
- and then put the buttons into the box one at a time.
- .PP
- By nesting the buttons within the box object, you force them to be its
- children. Each of the buttons must have both the SELECTABLE and RADIO BUTTON
- attributes set. When you are done, you may make the containing box
- invisible by setting its border to zero, but do not FLATTEN it!
- .PP
- Since each radio button represents a different option, you must usually
- assign a name to each object. When initializing the dialog, you must check
- which option is currently set, and turn on the corresponding button only. A
- chain of if-then-else structures assures that only one button will be selected.
- .PP
- At the conclusion of the dialog, you must check each button with selectp()
- and make the appropriate adjustments to internal variables. Again, an
- if-then-else chain is appropriate since only one button may be
- selected. Either deselect the chosen button within this chain or do
- them all at the end.
- .PP
- There is one common use of radio buttons in which you may short-cut this
- procedure. If the buttons each represent one possible value of a numeric
- variable, for instance, a set of selector buttons representing colors
- from zero to seven, then you can compute the initial object directly.
- .PP
- In order for this technique to work, you must use a special capability of the
- RCS. Insert the object corresponding to a zero value at the top (or left) of
- your array of buttons, then put the "one" button below (or right) of it, and so
- on.
- .PP
- When the buttons are complete, the SORT operation is used to guarantee that
- the top/left object is in fact the first child of the parent box with
- the others following in order. Due to the details of object tree
- structure (to be discussed in the next column), this will guarantee
- that these objects are contiguous in the resource.
- .PP
- If you assign a name (say BUTTON1) to the first button, then you can
- initialize the correct button with the call:
- .FB sel_obj()
- sel_obj(tree, BUTTON1 + field);
- .FE
- where field is the variable of interest.
- .PP
- When the dialog is complete, you can scan the radio buttons to compute the
- new value for the underlying variable. The encode() procedure in the download
- will do this. As always, remember to deselect the buttons at the end.
- .PP
- You can use offsets or multipliers if your variable's values don't start with
- zero or increment by one. If the values are irregular you may be able to use a
- lookup table, at the cost of additional code.
- .SH COMING UP NEXT
- In the next column, I will discuss the internal structure of object
- trees. Then we'll use that knowledge to build a piece of code which
- will "walk" an entire tree and apply a function to each object. We'll
- apply this code to do all of the button deselects with a single call!
- I'll also look at handling editable text fields and discuss some ways
- to alter a dialog's appearance at run-time.
- .SH DISPELL GREMLINS
- An editing error caused an omission in the first installment of ST PRO
- GEM. The window components RTARROW and DNARROW should have been
- listed along with HSLIDE as the horizontal equivalents of the vertical
- slider components which were discussed.
- .!
- .!
- .!*****************************************************************************
- .!* *
- .!* End Part 3 *
- .!* *
- .!*****************************************************************************
-